package com.sky.aop;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

@Aspect
@Component
@Slf4j
public class AutoFillAspect {
    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..)) && @annotation(com.sky.annotation.AutoFill)")
    public void autoFillPointCut() {
    }

    /**
     * 完成了公共字段的填充
     *
     * @param joinPoint
     * @throws NoSuchMethodException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    @Before("autoFillPointCut()")
    public void autoFill(JoinPoint joinPoint) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        log.info("公共字段填充逻辑开始...");
        //所有在com.sky.mapper中的接口里的方法，如果上面有AutoFill注解，都能够拦截到
        //解析到参数中的实体数据，然后将公共字段数据进行设置
        //1、先通过joinPoint获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        //2、获得所拦截的方法对象，获取方法上面的注解
        Method method = signature.getMethod();
        //3、判断注解是否有AutoFill注解，没有的话直接返回，如果有进一步实现自动填充的逻辑
        AutoFill autoFill = method.getAnnotation(AutoFill.class);

        Object[] args = joinPoint.getArgs();
        //没有参数，参数长度为0
        if (args==null||args.length==0) {
            return;
        }

        //4、自动填充，获取参数的实体对象
        Object entity = args[0];

        //5、通过字段反射技术进行设置值
        //字段反射
        //1.获取字节码对象
        Class<?> cls = entity.getClass();

        //公共数据
        LocalDateTime now = LocalDateTime.now();//当前时间
        Long currentId = BaseContext.getCurrentId();//当前操作的用户ID


        //新增，更新
        OperationType type = autoFill.value();
        if (type==OperationType.INSERT) {
            //新增：创建，更新的时间，创建，更新的用户

            //2.获取对应的方法
            Method createTimeMethod = cls.getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
            Method updateTimeMethod = cls.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method createUserMethod = cls.getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
            Method updateUserMethod = cls.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            //反射执行，调用方法
            createTimeMethod.invoke(entity, now);
            updateTimeMethod.invoke(entity, now);
            createUserMethod.invoke(entity, currentId);
            updateUserMethod.invoke(entity, currentId);

        } else if (type ==OperationType.UPDATE) {
            //更新：更新的时间，更新的用户
            Method updateTimeMethod = cls.getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
            Method updateUserMethod = cls.getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
            updateTimeMethod.invoke(entity, now);
            updateUserMethod.invoke(entity, currentId);
        }


    }

}
